package com.dctp.ems.controller;

import com.dctp.common.controller.BaseController;
import com.dctp.common.db.UserDb;
import com.dctp.common.service.TradeService;
import com.dctp.common.service.UserRoleChainService;
import com.dctp.common.utils.DateUtil;
import com.dctp.common.utils.StringUtil;
import com.dctp.common.utils.UUIDUtil;
import com.dctp.common.cache.UserCache;
import com.dctp.common.vo.FundChangeType;
import com.dctp.common.vo.JsonResult;
import com.dctp.common.vo.PageResult;
import com.dctp.ems.config.OpsLog;
import com.dctp.ems.interceptor.OpsLogInterceptor;
import com.jfinal.core.NotAction;
import com.jfinal.core.Path;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.sql.SqlKit;
import com.jfinal.plugin.activerecord.tx.Tx;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.time.LocalDateTime;
import java.util.stream.Collectors;

import com.jfinal.aop.Before;

@Path("/withdraw")
public class WithdrawController extends BaseController {

    /**
     * GET /withdraw/list
     * 分页查询提现记录，支持user_id、audit_status、create_time范围
     */
    public void list() {
        int page = getInt("currentPage", 1);
        int pageSize = getInt("pageSize", 10);
        QueryResult qr = buildWithdrawQuery();
        String select = "SELECT * ";
        String from = "FROM dctp_withdraw" + qr.where + " ORDER BY id DESC";
        var p = Db.paginate(page, pageSize, select, from, qr.params.toArray());
        List<Record> list = p.getList();
        for (Record r : list) {
            LocalDateTime createTime = r.getLocalDateTime("create_time");
            LocalDateTime auditTime = r.getLocalDateTime("audit_time");
            if (createTime != null) {
                r.set("create_time", DateUtil.format(createTime, "yyyy-MM-dd HH:mm:ss"));
            }
            if (auditTime != null) {
                r.set("audit_time", DateUtil.format(auditTime, "yyyy-MM-dd HH:mm:ss"));
            }
            Long uid = r.getLong("user_id");
            if (uid != null) {
                Record user = UserCache.getShowInfo(uid);
                r.set("user", user != null ? user.getColumns() : null);
            }
        }
        renderJson(JsonResult.successWithData(
            new PageResult<>(list, p.getTotalRow(), pageSize, page)
        ));
    }

    /**
     * POST /withdraw/audit/:id
     * 审核提现记录
     * 参数：audit_status(1=通过,2=拒绝), remark(可选)
     */
    @Before({Tx.class, OpsLogInterceptor.class})
    @OpsLog(module = "提现管理",
            action = "提现审核",
            table = "dctp_withdraw",
            fields = {"audit_status"})
    public void audit() {
        Record params = jsonBody();
        Long id = getParaToLong(0);
        Integer auditStatus = params.getInt("audit_status");
        String remark = params.get("remark","");
        if (id == null || auditStatus == null) {
            throw new RuntimeException("参数缺失");
        }
        Long auditorId = getUserId();
        Record withdraw = Db.findById("dctp_withdraw", id);
        if (withdraw == null) {
            throw new RuntimeException("记录不存在");
        }
        Integer withdrawAuditStatus = withdraw.getInt("audit_status");
        if (withdrawAuditStatus == null || withdrawAuditStatus != 0) {
            throw new RuntimeException("该订单已审核，不能重复操作");
        }
        int r = Db.update("UPDATE dctp_withdraw SET audit_status=?, auditor_id=?, audit_time=NOW(), remark=?, update_time=NOW() WHERE id=?",
                auditStatus, auditorId, remark, id);
        if (r == 0) {
            throw new RuntimeException("审核失败或记录不存在");
        }
        this.auditSingle(auditStatus,withdraw);
        renderJson(JsonResult.success());
    }

    @NotAction
    private void auditSingle(Integer auditStatus,Record withdraw) {
        BigDecimal amountFrom =  withdraw.getBigDecimal("amount_from");
        Long userId = withdraw.getLong("user_id");
        BigDecimal subBalance2 = withdraw.getBigDecimal("sub_balance2");
        Long id = withdraw.getLong("id");
        if (auditStatus == 1) {
            // 审核通过，实际业务可在此补充转账逻辑
            //写入资金流水
            BigDecimal balance = UserDb.getBalance(userId);
            //写入资金明细
            Record user = UserDb.findBasicById(userId);
            TradeService.saveFundFlow(user,FundChangeType.WITHDRAW,balance,balance.subtract(amountFrom),amountFrom.negate(),id,"提现");

//            if (subBalance2 != null && subBalance2.compareTo(BigDecimal.ZERO) > 0) {
//                //写入资金明细
//                BigDecimal beforeBalance = user.getBigDecimal("balance2");
//                TradeService.saveFundFlow(user, FundChangeType.EMS_OPS2, beforeBalance.add(subBalance2), beforeBalance, subBalance2.negate(),id, "1:1额度提现");
//            }
            setAttr("oldRecord", withdraw);
        }else {
            //审核不通过
            int updateRows = Db.update("UPDATE dctp_user SET balance = balance + ? WHERE id = ? ", amountFrom, userId);
            if (updateRows == 0) {
                throw new RuntimeException("审核失败");
            }

            if (subBalance2 != null && subBalance2.compareTo(BigDecimal.ZERO) > 0) {
                //写入资金明细
                int sbr = Db.update("update dctp_user set balance2 = balance2 + ? where id = ? ",subBalance2,userId);
                if (sbr == 0) {
                    throw new RuntimeException("审核失败");
                }
            }
        }
    }

    @Before(Tx.class)
    public void batchAudit() {
        Record params = jsonBody();
        String idsStr = params.getStr("ids");
        if (StringUtil.isEmpty(idsStr)) {
            renderJson(JsonResult.failWithMessage("参数缺失"));
            return;
        }
        List<Long> ids = Arrays.stream(idsStr.split(","))
                .map(String::trim)
                .map(Long::valueOf)
                .toList();

        Integer auditStatus = params.getInt("audit_status");
        String remark = params.get("remark", "");

        if (ids.isEmpty() || auditStatus == null) {
            throw new RuntimeException("参数缺失");
        }

        Long auditorId = getUserId();

        String joinSql = joinInSql(ids.size());
        List<Record> withdrawList = Db.find("SELECT * FROM dctp_withdraw WHERE id IN " + joinSql, ids.toArray());
        if (withdrawList == null || withdrawList.isEmpty()) {
            throw new RuntimeException("无有效记录");
        }

        for (Record withdraw : withdrawList) {
            Long id = withdraw.getLong("id");
            Integer withdrawAuditStatus = withdraw.getInt("audit_status");

            if (withdrawAuditStatus == null || withdrawAuditStatus != 0) {
                continue; // 已审核跳过
            }

            int updated = Db.update("UPDATE dctp_withdraw SET audit_status=?, auditor_id=?, audit_time=NOW(), remark=?, update_time=NOW() WHERE id=?",
                    auditStatus, auditorId, remark, id);

            if (updated == 0) {
                continue; // 更新失败
            }
            this.auditSingle(auditStatus,withdraw);
        }
        renderJson(JsonResult.success());
    }


    /**
     * GET /withdraw/export
     * 导出提现记录Excel，支持user_id、audit_status、create_time范围
     */
    public void export() {
        QueryResult qr = buildWithdrawQuery();
        String sql = "SELECT * FROM dctp_withdraw" + qr.where + " ORDER BY id DESC";
        List<Record> list = Db.find(sql, qr.params.toArray());
        try (Workbook wb = new XSSFWorkbook()) {
            Sheet sheet = wb.createSheet("提现记录");
            int rowIdx = 0;
            Row head = sheet.createRow(rowIdx++);
            String[] fields = {"id", "withdraw_sn", "user_id", "amount_from", "amount_to", "receive_amount", "exchange_rate", "chain_type", "withdraw_address", "tx_hash", "audit_status", "audit_time", "remark", "create_time"};
            String[] titles = {"ID", "提现流水号", "用户", "提现金额(HKDT)", "理论到账(USDT)", "实际到账(USDT)", "汇率", "链类型", "收款地址", "TxHash", "审核状态","审核时间", "备注", "创建时间"};
            for (int i = 0; i < titles.length; i++) head.createCell(i).setCellValue(titles[i]);
            for (Record r : list) {
                Row row = sheet.createRow(rowIdx++);
                Long uid = r.getLong("user_id");
                Record user = uid != null ? UserCache.getBasic(uid) : null;
                for (int i = 0; i < fields.length; i++) {
                    Object val;
                    switch (fields[i]) {
                        case "user_id":
                            val = "";
                            Record u = UserCache.getShowInfo(r.getLong("user_id"));
                            if (null != u) {
                                val = u.getStr("email");
                            }
                            break;
                        case "amount_from":
                        case "amount_to":
                        case "receive_amount":
                        case "exchange_rate":
                            val = r.getBigDecimal(fields[i]) != null ? r.getBigDecimal(fields[i]).toPlainString() : "";
                            break;
                        case "create_time": {
                            LocalDateTime createTime = r.getLocalDateTime("create_time");
                            val = createTime != null ? DateUtil.format(createTime) : "";
                            break;
                        }
                        case "audit_status": {
                            int auditStatus = r.getInt("audit_status");
                            val = auditStatus == 0 ? "待审核" : auditStatus == 1 ? "审核通过" : "审核不通过";
                            break;
                        }
                        case "audit_time": {
                            LocalDateTime auditTime = r.getLocalDateTime("audit_time");
                            val = auditTime != null ? DateUtil.format(auditTime) : "";
                            break;
                        }
                        default:
                            val = r.get(fields[i]) != null ? r.get(fields[i]) : "";
                    }
                    row.createCell(i).setCellValue(val.toString());
                }
                // 用户账号单独处理
                row.createCell(2).setCellValue(user != null ? user.getStr("login_account") : "");
            }
            String dateStr = DateUtil.format(DateUtil.now(), "yyyyMMdd");
            String randomStr = UUIDUtil.orderedUUID().substring(0, 8);
            String fileName = "提现记录-" + dateStr + "-" + randomStr + ".xlsx";
            HttpServletResponse resp = getResponse();
            resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            resp.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            wb.write(resp.getOutputStream());
            renderNull();
        } catch (Exception e) {
            throw new RuntimeException("导出失败", e);
        }
    }

    /**
     * 构建提现查询SQL和参数
     */
    private static class QueryResult {
        StringBuilder where;
        List<Object> params;
        QueryResult(StringBuilder where, List<Object> params) {
            this.where = where;
            this.params = params;
        }
    }
    private QueryResult buildWithdrawQuery() {
        Long userId = getParaToLong("user_id");
        Integer auditStatus = getParaToInt("audit_status", null);
        String startTime = getPara("start_time");
        String endTime = getPara("end_time");
        StringBuilder where = new StringBuilder(" WHERE 1=1 ");
        List<Object> params = new ArrayList<>();
        if (userId != null) {
            where.append(" AND user_id = ?");
            params.add(userId);
        }

        String tags = getPara("tags");
        if (StringUtil.isNotEmpty(tags)) {
            where.append(" AND user_id IN (SELECT id FROM dctp_user WHERE tags LIKE ?)");
            params.add("%" + tags + "%"); // 参数里加 % 通配符
        }

        if (auditStatus != null) {
            where.append(" AND audit_status = ?");
            params.add(auditStatus);
        }
        if (startTime != null && !startTime.isEmpty()) {
            where.append(" AND create_time >= ?");
            params.add(startTime);
        }
        if (endTime != null && !endTime.isEmpty()) {
            where.append(" AND create_time <= ?");
            params.add(endTime);
        }
        String filterField = getFilterField();
        Long filterUserId = getRequestUser().getLong("user_id");
        if (filterField != null && filterUserId != null) {
            where.append(" AND ").append(filterField).append(" = ?");
            params.add(filterUserId);
        }

        String roleKey = getPara("roleKey");
        Long roleUserId = getParaToLong("roleUserId");
        if (StringUtil.isNotEmpty(roleKey) && null != roleUserId) {
            where.append(" AND ").append(roleKey).append(" = ?");
            params.add(roleUserId);
        }

        return new QueryResult(where, params);
    }

    public String joinInSql(int size) {
        if (size <= 0) {
            throw new IllegalArgumentException("IN 子句参数数量必须大于0");
        }
        return "(" + String.join(",", Collections.nCopies(size, "?")) + ")";
    }
}
